module FETCH(clk, PC, enable, mem_data, mem_addr, icode, ifun, rA, rB, valC, valP, WAIT, mem_ub, mem_lb);
input [15:0] mem_data;
input clk;
input [31:0] PC;
input enable;

output reg [31:0] mem_addr;
output reg [3:0] icode;
output reg [3:0] ifun;
output reg [3:0] rA;
output reg [3:0] rB;
output reg [31:0] valC;
output reg [31:0] valP;
output reg WAIT;
output reg mem_ub;
output reg mem_lb;

reg [1:0] counter;

reg is_align;
  
always @(negedge clk) begin
  	//Primeiro ciclo de leitura
  	if(enable) begin	  
		if(counter == 0) begin
			if(is_align) begin
				icode = mem_data[7:4];
				ifun = mem_data[3:0];
				case(icode)
					0,1,9: begin 
						WAIT = 0;	      			
					end
					2,6,10,11: begin
						rA = mem_data[15:12];
						rB = mem_data[11:8];
						WAIT = 0;
					end
					3,4,5: begin
						rA = mem_data[15:12];
						rB = mem_data[11:8];
						WAIT = 1;
					end
					7,8: begin
						valC[7:0] = mem_data[15:8];
						WAIT = 1;
					end
					default: begin
						WAIT = 0;
					end
				endcase
			end else begin
				icode = mem_data[15:12];
				ifun = mem_data[11:8];
				case(icode)
					0,1,9: begin
						WAIT = 0;
					end
					2,6,10,11,3,4,5,7,8: begin
						WAIT = 1;
					end
					default: begin
						WAIT = 0;
					end
				endcase
			end
		
			//Set valP
			case(icode)
				0,1,9: valP = PC + 1;
				2,6,10,11: valP = PC + 2;
				3,4,5: valP = PC + 6;
				7,8: valP = PC + 5;
			endcase
			
			
		/*Segundo ciclo de leitura
		InstruÃ§Ãµes finalizada:
			0,1,9,2,6,10,11 se alinhado
			0,1,9 se nÃ£o alinhado
		*/
		end else if(counter == 1) begin
			if(is_align) begin
				case (icode)
					3,4,5: begin
						valC[15:0] = mem_data[15:0];
						WAIT = 1;
					end
					7,8: begin
						valC[23:8] = mem_data[15:0];
						WAIT = 1;
					end
					default: begin
						WAIT = 0;
					end
				endcase
			end else begin
				case(icode)
					2,6,10,11: begin
						rA = mem_data[7:4];
						rB = mem_data[3:0];
						WAIT = 0;
					end
					3,4,5: begin
						rA = mem_data[7:4];
						rB = mem_data[3:0];
						valC[7:0] = mem_data[15:8];
						WAIT = 1;
					end
					7,8: begin
						valC[15:0] = mem_data[15:0];
						WAIT = 1;
					end
					default: begin
						WAIT = 0;
					end
				endcase
			end
		/*terceiro ciclo de leitura
		InstruÃ§Ãµes finalizadas:
		0,1,9,2,6,10,11 alinhado ou nÃ£o
		*/
		end else if(counter == 2) begin
			if(is_align) begin
				case (icode)
					3,4,5: begin
						valC[31:16] = mem_data[15:0];
						WAIT = 0;
					end
					7,8: begin
						valC[31:24] = mem_data[7:0];
						WAIT = 0;
					end
					default: begin
						WAIT = 0;
					end
				endcase
			end else begin
				case (icode)
					3,4,5: begin
							valC[23:8] = mem_data[15:0];
							WAIT = 1;
					end
					7,8: begin
							valC[31:16] = mem_data[15:0];
							WAIT = 0;
					end
					default: begin
						WAIT = 0;
					end
				endcase
			end
		 /*quarto ciclo de leitura
		 InstruÃ§Ãµes finalizadas:
			todas se alinhado
		0,1,9,2,6,10,11,3,4,5 se nÃ£o alinhado
		 */
		 end else if(counter == 3) begin
			if(!is_align)begin
				case (icode)
					3,4,5: begin
						valC[31:24] = mem_data[7:0];
						WAIT = 0;
					end
					default: begin
						WAIT = 0;
					end
				endcase
			end
		end
    end 
    else begin
		WAIT = 0;
	end
end
  
always @(posedge clk or posedge enable) begin
	if(enable)begin
		mem_ub <= 1;
		mem_lb <= 1;
		if(!WAIT)begin
			//se pc for impar ele comeÃ§a a ler do segundo byte da celula de memÃ³ria
			//acesso desalinhado
			mem_addr <= (PC >> 1);
			is_align <= !PC[0];
			counter <= 2'b0;
		end else begin
			mem_addr <= mem_addr + 1;
			counter <= counter + 2'b1;
		end
	end
	else begin
		counter <= 0;
	end
end
endmodule
